﻿/**
 * TextUtil class
 * This class holds all the utility function for manipulating a string
 * 
 * @author: Veronica Liesaputra
 */
class RealisticBooks.TextUtil {
/**
 * Replace the HTML entities to the HTML decimal values
 * Parameters:
 * @param {String} str the specified string
 * Returns:
 * @return {String} the string with all of its HTML encoding entities 
 * converted to HTML decimal values
 */
public static function convertHTMLEntities (str:String):String {
	var htmlEntities:Array = ["&nbsp;", "&iexcl;", "&cent;", "&pound;", "&curren;", 
						"&yen;", "&brvbar;", "&sect;", "&uml;", "&copy;", 
						"&ordf;","&laquo;", "&not;", "&shy;", "&reg;", "&macr;",
						"&deg;", "&plusmn;", "&sup2;", "&sup3;", "&acute;", 
						"&micro;", "&para;", "&middot;", "&cedil;", "&sup1;", 
						"&ordm;", "&raquo;", "&frac14;", "&frac12;", "&frac34;",
						"&iquest;", "&Agrave;", "&Aacute;", "&Acirc;", "&Atilde;",
						"&Auml;", "&Aring;", "&AElig;", "&Ccedil;", "&Egrave;",
						"&Eacute;", "&Ecirc;", "&Euml;", "&Igrave;", "&Iacute;",
						"&Icirc;", "&Iuml;", "&ETH;", "&Ntilde;", "&Ograve;",
						"&Oacute;", "&Ocirc;", "&Otilde;", "&Ouml;", "&times;",
						"&Oslash;", "&Ugrave;", "&Uacute;", "&Ucirc;", "&Uuml;",
						"&Yacute;", "&THORN;", "&szlig;", "&agrave;", "&aacute;",
						"&acirc;", "&atilde;", "&auml;", "&aring;", "&aelig;",
						"&ccedil;", "&egrave;", "&eacute;", "&ecirc;", "&euml;",
						"&igrave;","&iacute;", "&icirc;", "&iuml;", "&eth;",
						"&ntilde;", "&ograve;", "&oacute;", "&ocirc;", "&otilde;",
						"&ouml;", "&divide;", "&oslash;", "&ugrave;", "&uacute;",
						"&ucirc;", "&uuml;", "&yacute;", "&thorn;", "&yuml;",
						"&fnof;", "&Alpha;", "&Beta;", "&Gamma;", "&Delta;", 
						"&Epsilon;", "&Zeta;", "&Eta;", "&Theta;", "&Iota;", 
						"&Kappa;", "&Lambda;", "&Mu;", "&Nu;", "&Xi;", "&Omicron;", 
						"&Pi;", "&Rho;", "&Sigma;", "&Tau;", "&Upsilon;", "&Phi;", 
						"&Chi;", "&Psi;", "&Omega;", "&alpha;", "&beta;", "&gamma;", 
						"&delta;", "&epsilon;", "&zeta;", "&eta;", "&theta;", 
						"&iota;", "&kappa;", "&lambda;","&mu;", "&nu;", "&xi;", 
						"&omicron;", "&pi;", "&rho;", "&sigmaf;", "&sigma;", 
						"&tau;", "&upsilon;", "&phi;", "&chi;", "&psi;", 
						"&omega;", "&thetasym;", "&upsih;", "&piv;", "&bull;", 
						"&hellip;", "&prime;", "&Prime;", "&oline;", "&frasl;", 
						"&weierp;", "&image;", "&real;", "&trade;", "&alefsym;",
						"&larr;", "&uarr;", "&rarr;", "&darr;", "&harr;", 
						"&crarr;", "&lArr;","&uArr;", "&rArr;", "&dArr;", 
						"&hArr;", "&forall;", "&part;", "&exist;", "&empty;", 
						"&nabla;", "&isin;", "&notin;", "&ni;", "&prod;", "&sum;", 
						"&minus;", "&lowast;", "&radic;", "&prop;", "&infin;", 
						"&ang;", "&and;", "&or;", "&cap;", "&cup;", "&int;", 
						"&there4;", "&sim;", "&cong;", "&asymp;", "&ne;", "&equiv;", 
						"&le;", "&ge;", "&sub;", "&sup;", "&nsub;", "&sube;", 
						"&supe;", "&oplus;", "&otimes;", "&perp;", "&sdot;", 
						"&lceil;", "&rceil;", "&lfloor;", "&rfloor;", "&lang;", 
						"&rang;", "&loz;", "&spades;", "&clubs;", "&hearts;", 
						"&diams;", "&quot;", "&amp;", "&lt;", "&gt;", "&OElig;", 
						"&oelig;", "&Scaron;", "&scaron;", "&Yuml;", "&circ;", 
						"&tilde;", "&ensp;", "&emsp;", "&thinsp;", "&zwnj;", 
						"&zwj;", "&lrm;", "&rlm;", "&ndash;", "&mdash;", "&lsquo;", 
						"&rsquo;", "&sbquo;", "&ldquo;", "&rdquo;", "&bdquo;", 
						"&dagger;", "&Dagger;", "&permil;", "&lsaquo;", "&rsaquo;", 
						"&euro;"];
	var numberEntities:Array = ["<#>160;", "<#>161;", "<#>162;", "<#>163;", "<#>164;", 
						  "<#>165;", "<#>166;", "<#>167;", "<#>168;", "<#>169;", 
						  "<#>170;", "<#>171;","<#>172;", "<#>173;", "<#>174;", 
						  "<#>175;", "<#>176;", "<#>177;", "<#>178;", "<#>179;", 
						  "<#>180;", "<#>181;", "<#>182;", "<#>183;", "<#>184;",
						  "<#>185;", "<#>186;", "<#>187;", "<#>188;", "<#>189;",
						  "<#>190;", "<#>191;", "<#>192;", "<#>193;", "<#>194;",
						  "<#>195;", "<#>196;", "<#>197;", "<#>198;", "<#>199;",
						  "<#>200;", "<#>201;", "<#>202;", "<#>203;", "<#>204;",
						  "<#>205;", "<#>206;", "<#>207;", "<#>208;", "<#>209;",
						  "<#>210;", "<#>211;", "<#>212;", "<#>213;", "<#>214;",
						  "<#>215;", "<#>216;", "<#>217;", "<#>218;", "<#>219;", 
						  "<#>220;", "<#>221;", "<#>222;", "<#>223;", "<#>224;",
						  "<#>225;", "<#>226;", "<#>227;", "<#>228;", "<#>229;",
						  "<#>230;", "<#>231;", "<#>232;", "<#>233;", "<#>234;",
						  "<#>235;", "<#>236;", "<#>237;", "<#>238;", "<#>239;",
						  "<#>240;", "<#>241;", "<#>242;", "<#>243;", "<#>244;",
						  "<#>245;", "<#>246;", "<#>247;", "<#>248;", "<#>249;",
						  "<#>250;", "<#>251;", "<#>252;", "<#>253;", "<#>254;",
						  "<#>255;", "<#>402;", "<#>913;", "<#>914;", "<#>915;",
						  "<#>916;", "<#>917;", "<#>918;", "<#>919;", "<#>920;",
						  "<#>921;", "<#>922;", "<#>923;", "<#>924;", "<#>925;",
						  "<#>926;", "<#>927;", "<#>928;", "<#>929;", "<#>931;",
						  "<#>932;", "<#>933;", "<#>934;", "<#>935;", "<#>936;",
						  "<#>937;", "<#>945;", "<#>946;", "<#>947;", "<#>948;",
						  "<#>949;", "<#>950;", "<#>951;", "<#>952;", "<#>953;",
						  "<#>954;", "<#>955;", "<#>956;", "<#>957;", "<#>958;",
						  "<#>959;", "<#>960;", "<#>961;", "<#>962;", "<#>963;",
						  "<#>964;", "<#>965;", "<#>966;", "<#>967;", "<#>968;",
						  "<#>969;", "<#>977;", "<#>978;", "<#>982;", "<#>8226;",
						  "<#>8230;", "<#>8242;", "<#>8243;", "<#>8254;", "<#>8260;",
						  "<#>8472;", "<#>8465;", "<#>8476;", "<#>8482;", "<#>8501;",
						  "<#>8592;", "<#>8593;", "<#>8594;", "<#>8595;", "<#>8596;",
						  "<#>8629;", "<#>8656;", "<#>8657;", "<#>8658;", "<#>8659;",
						  "<#>8660;", "<#>8704;", "<#>8706;", "<#>8707;", "<#>8709;",
						  "<#>8711;", "<#>8712;", "<#>8713;", "<#>8715;", "<#>8719;",
						  "<#>8721;", "<#>8722;", "<#>8727;", "<#>8730;", "<#>8733;", 
						  "<#>8734;", "<#>8736;", "<#>8743;", "<#>8744;", "<#>8745;", 
						  "<#>8746;", "<#>8747;", "<#>8756;", "<#>8764;", "<#>8773;", 
						  "<#>8776;", "<#>8800;", "<#>8801;", "<#>8804;", "<#>8805;", 
						  "<#>8834;", "<#>8835;", "<#>8836;", "<#>8838;", "<#>8839;", 
						  "<#>8853;", "<#>8855;", "<#>8869;", "<#>8901;", "<#>8968;", 
						  "<#>8969;", "<#>8970;", "<#>8971;", "<#>9001;", "<#>9002;", 
						  "<#>9674;", "<#>9824;", "<#>9827;", "<#>9829;", "<#>9830;", 
						  "<#>34;", "<#>38;", "<#>60;", "<#>62;", "<#>338;", "<#>339;", 
						  "<#>352;", "<#>353;", "<#>376;", "<#>710;", "<#>732;", 
						  "<#>8194;", "<#>8195;", "<#>8201;", "<#>8204;", "<#>8205;", 
						  "<#>8206;", "<#>8207;", "<#>8211;", "<#>8212;", "<#>8216;", 
						  "<#>8217;", "<#>8218;", "<#>8220;", "<#>8221;", "<#>8222;", 
						  "<#>8224;", "<#>8225;", "<#>8240;", "<#>8249;", "<#>8250;",
						   "<#>8364;"];
	str = TextUtil.unprotectEntities (str);
	//need to embed latin 1, greek, korean basuc hongul if we want to use this
	if ((str.indexOf('&') != -1) && (str.indexOf(';') != -1)) {
		//maybe there's HTML entities encoding
		//first we need to make sure that the HTML decimal encoding is protected
		str = TextUtil.replaceString(str, "&#", "<#>");
		for (var i:Number = 0; i < htmlEntities.length; i++) {
			//go through the list of html entities
			str = TextUtil.replaceString(str, htmlEntities[i], numberEntities[i]);
			if (str.indexOf('&') == -1) {
				break;
			}
		}
		//unmasked the protected decimal encoding
		str = TextUtil.replaceString(str, "<#>", "&#");
	}
	
	return str;
}
/**
 * For saving the file
 */
public static function protectEntities (str:String):String {
	str = TextUtil.replaceString(str, "&#", "@&#@");
	return str;
}
/**
 * When reading the file
 */
public static function unprotectEntities (str:String):String {
	str = TextUtil.replaceString(str, "@&#@", "&#");
	str = TextUtil.replaceString(str, "@&amp;#@", "&#");
	return str;
}
/**
 * Replace the double quotes occurence with its escape characters
 * Parameters:
 * @param {String} str the specified string
 * Returns:
 * @return {String} the string with all the quotes escaped
 */
public static function escapeQuotes (str:String):String {
	var res:String = TextUtil.replaceString(str,'"','\\\"');
	return res;
}
/**
 * Replace the double quotes escape characters occurence 
 * with its actual characters 
 * Parameters:
 * @param {String} str the specified string
 * Returns:
 * @return {String} the string with all the quotes unescaped
 */
public static function unescapeQuotes (str:String):String {
	var res:String = TextUtil.replaceString(str,'\"','"');
	return res;
}
/**
 * Remove the specified text from the specified string
 * Parameters:
 * @param {String} txt the specified text
 * @param {String} str the specified string
 * Returns:
 * @return {String} The specified string without the specified 
 * text in it
 */
public static function removeTxtFromString(txt:String, str:String):String {
	var res:String = TextUtil.replaceString(str, txt, "");
	return res;
}
/**
 * Replace every occurence of the specified string with the specified text
 * Paramters:
 * @param {String} str the string we want to operates on
 * @param {String} txt the string we want to replace
 * @param {String} val the string we will replace the text with
 * Returns:
 * @return {String} the string with all the specified string occurences 
 * replace with the specified text
 */
public static function replaceString (str:String, txt:String, val:String):String {
	if (TextUtil.strIsEmpty(str,false) == true)
		return str;
	
	var res:String = str.split(txt).join(val);
	return res;
}
/**
 * Convert color value into string formatted color
 * Parameters:
 * @param {Number} val the hexcode color value
 * Returns:
 * @return {String} the hexcode color as a string
 */
public static function colorToString(val:Number):String {
	var c:String = Math.abs(val).toString(16);
	while(c.length < 6)
		c = "0" + c;
	
	return ("0x" + c.toUpperCase());
}
/**
 * Testing whether the string is null or empty
 * Parameters:
 * @param {String} str 		the string to be tested
 * @param {Boolean} isTrim	whether the whitespaces
 *							in the beginning/end is acceptable
 * Returns:
 * @return {Boolean} whether the string is empty 
 */
public static function strIsEmpty (str:String, isTrim:Boolean):Boolean {
	if ((str == undefined) || (str == null) || (str.length == 0)) {
		return true;
	}
	
	if ((isTrim == true) && (TextUtil.trim(str).length == 0)) {
		return true;
	}
	
	return false;
}
/**
 * Trim whitespaces (tab, linefeed, carriage and space) from
 * a string
 * Parameters:
 * @param {String} str the string to be trimmed
 * Returns:
 * @return {String} string without whitespaces at the start
 * and the end of the string
 */
public static function trim (str:String):String {
	if ((str == undefined) || (str == null) || (str.length == 0)) {
		return str;
	}

	var spaceList:Object = new Object();
	spaceList[' '] = true;
	spaceList['\n'] = true;
	spaceList['\t'] = true;
	spaceList['\r'] = true;
	
	var sCount:Number = 0;//start index
	for (var i:Number = 0; i < str.length; i++) {
		if (spaceList[str.charAt(i)] == null) {
			break;
		}
		sCount++;
	}
	
	var eCount:Number = str.length - 1;//end index
	for (var i:Number = str.length - 1; i > sCount; i--) {
		if (spaceList[str.charAt(i)] == null) {
			break;
		}
		eCount--;
	}
	
	var nStr:String = str.substring(sCount, eCount + 1);
	return nStr;
}
/**
 * Remove string that is empty from the array
 * Parameters:
 * @param {Array} arr the specified array
 * Returns:
 * @return {Array} an array without any empty string
 */
public static function removeEmptyStrings(arr:Array):Array {
	var nArr:Array = new Array();
	for (var i:Number = 0; i < arr.length; i++) {
		if (TextUtil.strIsEmpty(arr[i],true) == false)
			nArr.push(TextUtil.trim(arr[i]));
	}
	return nArr;
}
/**
 * Convert the string to the boolean value
 * Parameters:
 * @param {String} str the string
 * Returns:
 * @return {Boolean} the boolean value
 */
public static function stringToBoolean (str:String):Boolean {
	if ((TextUtil.strIsEmpty(str, true) == true) || 
		(str.toLowerCase() == "true"))
		return true;
	else
		return false;
}
/**
 * Remove newline and extra spaces in the text
 * Parameters:
 * @param {String} s_txt the text to be cleaned
 * Returns:
 * @return {String} The clean text
 */
public static function cleanSpaceFromText (s_text:String):String {
	s_text = TextUtil.replaceMultString (["\n","\r","  "], s_text, " ");
	while (s_text.indexOf("  ") != -1) {
		s_text = TextUtil.replaceString (s_text, "  ", " ");//remove all extra space
	}
	s_text = TextUtil.convertHTMLEntities(s_text);//convert the HTML entities
	return s_text;
}
/**
 * Replace all the term in the array that are found in the string 
 * with the specified text
 * Parameters:
 * @param {Array} termArr the list of term that we want to replace
 * @param {String} s_text the text to be cleaned
 * @param {String} str	  the text we replace each term with
 * Returns:
 * @return {String} the clean text
 */
public static function replaceMultString (termArr:Array, s_text:String, str:String):String {
	for (var i:Number = 0; i < termArr.length; i++) {
		s_text = TextUtil.replaceString(s_text, termArr[i], str);
	}
	return s_text;
}
/**
 * See whether any of the string in the array is found
 * inside the specified text
 * Parameters:
 * @param {Array}  queryArr	the list of string we want to find
 * @param {String} str 		the text we want to check
 * Returns:
 * @return {Boolean} whether we find any of the term in queryArr in str
 */
public static function findTerm (queryArr:Array, str:String):Boolean {
	for (var i:Number = 0; i < queryArr.length; i++) {
		if (str.indexOf(""+queryArr[i]) != -1) {
			return true;
		}
	}
	return false;
}
/**
 * See whether any of the characters in the array is found
 * inside the specified text at the specified location
 * Parameters:
 * @param {Array}  queryArr	the list of characters we want to find
 * @param {String} str 		the text we want to check
 * @param {Number} loc		the character location
 * Returns:
 * @return {Boolean} whether we find any of the character in queryArr in str
 */
public static function findCharAt (queryArr:Array, str:String, loc:Number):Boolean {
	var txt:String = str.charAt(loc);
	return findTerm(queryArr, txt);
}
}